/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-11-26
 * Time: 23:19
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;

using tools;
using patterns;

using Labb4.Entity;
using Labb4.Media;
using Labb4.Media.Sfx;
using Labb4.Main;
using Labb4.Pooman.Misc;
using Labb4.Pooman.Game;

namespace Labb4.Event
{
	/// <summary>
	/// Description of Event.
	/// </summary>
	public class Event
	{
		#region members
		
		//private EntityFactory		Factory;
		/// <summary>
		/// If the event has a picture entity, it's referenced here
		/// </summary>
		private BasicEntity			m_EventImage;
		/// <summary>
		/// If the event has an animation, then this is the reference
		/// </summary>
		private BasicEntity			m_EventAnimation;
		/// <summary>
		/// If the event has a sound, this is its reference
		/// </summary>
		private Audio				m_EventAudio;
		
		/// <summary>
		/// The specs for the event, or the parameters if you will
		/// </summary>
		private List<EventInfo>		m_EventSpecs;
		
		/// <summary>
		/// This is a reference to the EntityManager, but in this context it's only used to get the current time
		/// </summary>
		private EntityManager		m_Time;
		/// <summary>
		/// Time passed since the event started playing. Unit is (ms)
		/// </summary>
		private int					m_Counter;
		/// <summary>
		/// If this is true, the event will go through its event infos, and play, so to speak
		/// </summary>
		private bool				m_Playing;
		/// <summary>
		/// When the event has finished (either by a call to stop, or by an event of type "endevent") this will be true
		/// </summary>
		private bool				m_HasPlayed;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor of Event, initializes members through the information found in a file
		/// </summary>
		/// <param name="eventConfigFile">A document holding all the information about the event</param>
		public Event(string eventConfigFile)
		{
			m_EventImage = null;
			m_EventAnimation = null;
			m_EventAudio = null;
			
			m_EventSpecs = new List<EventInfo>();
			
			m_Time = EntityManager.Instance;
			m_Counter = 0;
			m_Playing = false;
			m_HasPlayed = false;
			
			FactoryMethod<BasicEntity> factory = null;
			Config config = new Config();
			
			//read config file, and create event accordingly
			if(MainForm.ErrorCheck(config.Open(eventConfigFile)))
			{
				bool hasPicture = false;
				bool hasAnimation = false;
				bool hasControl = false;
				bool hasAudio = false;
				
				if(MainForm.ErrorCheck(config.GetBool("event_animation", ref hasAnimation)) &&
				   MainForm.ErrorCheck(config.GetBool("event_picture", ref hasPicture)) &&
				   MainForm.ErrorCheck(config.GetBool("event_control", ref hasControl)) &&
				   MainForm.ErrorCheck(config.GetBool("event_sound", ref hasAudio)))
				{
					Control control = null;
					
					if(hasControl)
					{
						string controlType = "";
						
						if(MainForm.ErrorCheck(config.GetString("event_control_type", ref controlType)))
						{
							if(controlType.Equals("destination"))
							{
								control = new ControlDestination();
							}
							
							if(controlType.Equals("macro"))
							{
								string macroConfigFile = "";
								
								if(MainForm.ErrorCheck(config.GetString("control_macro_file", ref macroConfigFile)))
								{
									control = new ControlPadMacro(Properties.Instance.StartPath + macroConfigFile);
								}
							}
						}
					}
					
					if(hasPicture)
					{
						string pictureEntityConfigFile = "";
						
						if(MainForm.ErrorCheck(config.GetString("picture_entity_config_file", ref pictureEntityConfigFile)))
						{
							factory = new PictureEntityFactory();
							m_EventImage = factory.GetProduct(Properties.Instance.StartPath + pictureEntityConfigFile);
							
							int x = 0;
							int y = 0;
							float dir = 0.0f;
							float vel = 0.0f;
							
							if(MainForm.ErrorCheck(config.GetInt("image_entity_x", ref x)) &&
							   MainForm.ErrorCheck(config.GetInt("image_entity_y", ref y)) &&
							   MainForm.ErrorCheck(config.GetFloat("image_entity_dir", ref dir)) &&
							   MainForm.ErrorCheck(config.GetFloat("image_entity_vel", ref vel)))
							{
								m_EventImage.Xpos = x;
								m_EventImage.Ypos = y;
								m_EventImage.Direction = dir;
								m_EventImage.Velocity = vel;
							}
							
							if(hasControl)
							{
								m_EventImage.Controler = control;
								
								if(control is ControlDestination)
								{
									LoadDestinations(control, config);
								}
							}
						}
					}
					
					if(hasAnimation)
					{
						string spriteEntityConfigFile = "";
						
						if(MainForm.ErrorCheck(config.GetString("sprite_entity_config_file", ref spriteEntityConfigFile)))
						{
							factory = new SpriteEntityFactory();
							m_EventAnimation = factory.GetProduct(Properties.Instance.StartPath + spriteEntityConfigFile);
							
							int x = 0;
							int y = 0;
							float dir = 0.0f;
							float vel = 0.0f;
							
							if(MainForm.ErrorCheck(config.GetInt("sprite_entity_x", ref x)) &&
							   MainForm.ErrorCheck(config.GetInt("sprite_entity_y", ref y)) &&
							   MainForm.ErrorCheck(config.GetFloat("sprite_entity_dir", ref dir)) &&
							   MainForm.ErrorCheck(config.GetFloat("sprite_entity_vel", ref vel)))
							{
								m_EventAnimation.Xpos = x;
								m_EventAnimation.Ypos = y;
								m_EventAnimation.Direction = dir;
								m_EventAnimation.Velocity = vel;
							}
							
							if(hasControl)
							{
								m_EventAnimation.Controler = control;
								
								if(control is ControlDestination)
								{
									LoadDestinations(control, config);
								}
							}
						}
					}
					
					if(hasAudio)
					{
						string audioFile = "";
						
						if(MainForm.ErrorCheck(config.GetString("event_sound_file", ref audioFile)))
						{
							m_EventAudio = MediaManager.Instance.GetAudio(Properties.Instance.StartPath + audioFile);
						}
					}
				}
				
				int infos = 0;
				
				if(MainForm.ErrorCheck(config.GetInt("event_infos", ref infos)))
				{
					string paramPart1 = "event_info_";
					string paramPart2A = "_task";
					string paramPart2B = "_time";
					string paramPart2C = "_specs";
					string paramPart2D = "_spec_";
					
					string task = "";
					int time = 0;
					int specs = 0;
					string spec = "";
					
					EventInfo info = null;
					
					for(int i = 0; i < infos; i++)
					{
						if(MainForm.ErrorCheck(config.GetString(paramPart1 + i.ToString() + paramPart2A, ref task)) &&
						   MainForm.ErrorCheck(config.GetInt(paramPart1 + i.ToString() + paramPart2B, ref time)) &&
						   MainForm.ErrorCheck(config.GetInt(paramPart1 + i.ToString() + paramPart2C, ref specs)))
						{
							info = new EventInfo(time, task);
							
							for(int j = 0; j < specs; j++)
							{
								if(MainForm.ErrorCheck(config.GetString(paramPart1 + i.ToString() + paramPart2D + j.ToString(), ref spec)))
								{
									info.AddSpecifics(spec);
								}
							}
							
							m_EventSpecs.Add(info);
						}
					}
				}
			}
			
			EventManager.Instance.AddEvent(this);
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Starts playing the event
		/// </summary>
		public void PlayEvent()
		{
			m_Playing = true;
			m_Counter = 0;
			
			if(m_EventImage != null)
			{
				m_EventImage.Activate(m_Time.CurrentTime);
			}
			
			if(m_EventAnimation != null)
			{
				m_EventAnimation.Activate(m_Time.CurrentTime);
			}
		}
		
		/// <summary>
		/// Stops the event
		/// </summary>
		public void StopEvent()
		{
			m_Playing = false;
			m_HasPlayed = true;
			
			if(m_EventImage != null)
			{
				m_EventImage.Deactivate();
			}
			
			if(m_EventAnimation != null)
			{
				m_EventAnimation.Deactivate();
			}
		}
		
		/// <summary>
		/// Updates the event, moves on to next event spec, and so on
		/// </summary>
		/// <param name="deltaTime">The time passed since the last call to update. Unit is (ms)</param>
		public void UpdateEvent(ref int deltaTime)
		{
			if(m_Playing)
			{
				m_Counter += deltaTime;
				
				if(m_EventSpecs.Count > 0)
				{
					if(m_Counter > m_EventSpecs[0].Time)
					{
						EventInfo info = m_EventSpecs[0];
						m_EventSpecs.RemoveAt(0);
						
						//deploy next part of event
						if(info.Task.Equals("playsound"))
						{
							if(m_EventAudio != null)
							{
								//playsound should have two parameters, first one is volume, second is pan
								if(info.Count == 2)
								{
									m_EventAudio.Play(int.Parse(info[0]), int.Parse(info[1]));
								}
							}
						}
						
						if(info.Task.Equals("playanimation"))
						{
							if(m_EventAnimation != null)
							{
								//playanimation should have one parameter, name of the animation
								if(info.Count == 1)
								{
									m_EventAnimation.SelectAnimation(info[0]);
								}
							}
						}
						
						if(info.Task.Equals("endevent"))
						{
							if(m_EventImage != null)
							{
								m_EventImage.Deactivate();
							}
							
							if(m_EventAnimation != null)
							{
								m_EventAnimation.Deactivate();
							}
							
							m_Playing = false;
							m_HasPlayed = true;
						}
					}
				}
			}
		}
		
		/// <summary>
		/// Is this ever used?
		/// </summary>
		/// <param name="info"></param>
		public void AddEventInfo(EventInfo info)
		{
			m_EventSpecs.Add(info);
		}
		
		#endregion
		
		#region properties
		
		/// <summary>
		/// True if the event is playing, otherwise false (get)
		/// </summary>
		public bool Playing
		{
			get
			{
				return m_Playing;
			}
		}
		
		/// <summary>
		/// True if the event has allready played, otherwise false (get)
		/// </summary>
		public bool HasPlayed
		{
			get
			{
				return m_HasPlayed;
			}
		}
		
		#endregion
		
		#region private methods
		
		/// <summary>
		/// Loads destinations to a controler of type ControlDestination
		/// </summary>
		/// <param name="control">The control to load the destinations into</param>
		/// <param name="config">The file to load destination points from</param>
		private void LoadDestinations(Control control, Config config)
		{
			int destinations = 0;
			
			if(MainForm.ErrorCheck(config.GetInt("control_destinations", ref destinations)))
			{
				string paramPart1 = "control_destination_";
				string paramPart2A = "_x";
				string paramPart2B = "_y";
				string paramPart2C = "_vel";
				
				int destX = 0;
				int destY = 0;
				float vel = 0.0f;
				
				for(int i = 0; i < destinations; i++)
				{
					if(MainForm.ErrorCheck(config.GetInt(paramPart1 + i.ToString() + paramPart2A, ref destX)) &&
					   MainForm.ErrorCheck(config.GetInt(paramPart1 + i.ToString() + paramPart2B, ref destY)) &&
					   MainForm.ErrorCheck(config.GetFloat(paramPart1 + i.ToString() + paramPart2C, ref vel)))
					{
						control.AddDestination(destX, destY, vel);
					}
				}
			}
		}
		
		#endregion
	}
}
